package com.hube.platform.tenant.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hube.platform.tenant.configuration.DynamicDataSource;
import com.hube.platform.tenant.constant.AppConstant;
import com.hube.platform.tenant.constant.StatusEnum;
import com.hube.platform.tenant.entity.dto.TenantDataBaseConfigDTO;
import com.hube.platform.tenant.entity.po.TenantDataBaseConfigPO;
import com.hube.platform.tenant.exception.DefaultErrorObject;
import com.hube.platform.tenant.exception.ServerError;
import com.hube.platform.tenant.helper.ApplicationContextHelper;
import com.hube.platform.tenant.helper.FacadeBuilder;
import com.hube.platform.tenant.helper.LiquibaseRunner;
import com.hube.platform.tenant.mapper.TenantInfoMapper;
import com.hube.platform.tenant.service.TenantInfoService;
import com.hube.platform.tenant.util.Assert;
import com.zaxxer.hikari.HikariConfig;
import liquibase.exception.LiquibaseException;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * @author : Aaron
 * @date : 2022/6/2
 */
@Service
public class TenantInfoServiceImpl extends ServiceImpl<TenantInfoMapper, TenantDataBaseConfigPO> implements TenantInfoService {

    private static final Logger log = LoggerFactory.getLogger(TenantInfoServiceImpl.class);

    @Autowired
    private LiquibaseRunner liquibaseRunner;

    private static final MapperFacade facade = FacadeBuilder.mapperFactory.getMapperFacade();

    @Override
    public List<TenantDataBaseConfigPO> getBaseInfoList() {
        LambdaQueryWrapper<TenantDataBaseConfigPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TenantDataBaseConfigPO::getStatus, StatusEnum.ENABLE.code());
        return baseMapper.selectList(wrapper);
    }

    @Override
    public TenantDataBaseConfigPO getTenantInfoById(String tenantId) {
        Assert.notNull(tenantId, DefaultErrorObject.OBJECT_NOT_NULL, "租户ID");
        LambdaQueryWrapper<TenantDataBaseConfigPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TenantDataBaseConfigPO::getTenantId, tenantId);
        TenantDataBaseConfigPO tenantInfo = baseMapper.selectOne(wrapper);
        Assert.notNull(tenantInfo, DefaultErrorObject.CONTENT_NOT_FOUND, "租户ID");
        int status = tenantInfo.getStatus();
        Assert.isTrue(StatusEnum.ENABLE.equals(status), ServerError.DISABLE_ERROR);
        return tenantInfo;
    }

    @Override
    public boolean createTenant(TenantDataBaseConfigDTO dto) {
        TenantDataBaseConfigPO configDO = facade.map(dto, TenantDataBaseConfigPO.class);
        //TODO 其他基础校验，唯一校验
        saveOrUpdate(configDO);
        //创建数据源，同步数据脚本
        try {
            liquibaseRunner.init(Arrays.asList(configDO));
        } catch (LiquibaseException e) {
            log.error("----初始化数据库失败----，{}，{}", dto, e);
            //设置为禁用
            configDO.setStatus(StatusEnum.DISABLE.code());
            saveOrUpdate(configDO);
            return false;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reloadDatasource(String id, TenantDataBaseConfigDTO dto) {
        //更新数据
        TenantDataBaseConfigPO configDO = facade.map(dto, TenantDataBaseConfigPO.class);
        configDO.setId(id);
        saveOrUpdate(configDO);
        //更新数据源
        DynamicDataSource dynamicDataSource = (DynamicDataSource) ApplicationContextHelper.getBean(AppConstant.DYNAMIC_DATA_SOURCE);
        dynamicDataSource.updateDataSource(dto.getTenantId(), dto.getDatabaseName(), facade.map(dto, HikariConfig.class));
        return true;
    }
}
